/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 * Description: image sender
 */
#ifndef IMAGE_SENDER_H
#define IMAGE_SENDER_H

#include "image_sender_base.h"
#include "util.h"
#include "mdc/cam/camera/cameradecodedmbufserviceinterface_skeleton.h"

using Skeleton = mdc::cam::camera::skeleton::CameraDecodedMbufServiceInterfaceSkeleton;

class ImageSender : public ImageSenderBase<Skeleton> {
public:
    ImageSender() = default;
    ImageSender(uint32_t id, cv::Size s, std::string dir) : ImageSenderBase<Skeleton>(id, s, dir)
    {
        sourceYuvPath = dir;
        if (dir.back() != '/') {
            sourceYuvPath += std::string("/") += "imageSource.yuv";
        } else {
            sourceYuvPath += "imageSource.yuv";
        }
#ifdef SAVE_SENDER_FILE
        fpYuv = fopen(sourceYuvPath.c_str(), "wb+");
#endif
        sec = std::chrono::high_resolution_clock::now();
    }

    ~ImageSender() = default;

    bool RegisterSender()
    {
        std::cout << "Begin register normal image sender." << std::endl;
        auto result = ImageSenderBase<Skeleton>::RegisterSender();
        std::cout << "Finished to register normal image sender." << std::endl;
        return result;
    }

    int retImageSender = -1;
    void FillImageAndSend(std::string imgPath, uint32_t seq, int32_t *flag) override
    {
        std::string path = dir;
        std::string postfix = g_comPara.fileType;
        bool isLoop = g_comPara.loop;
        std::cout << "dir : " << dir << "\t"
            << "postfix :" << postfix << std::endl;
        std::vector<std::string> files;
        int32_t fileCnt = GetFilesBySort(path, files, g_comPara.fileType);
        if (fileCnt == 0) {
            std::cout << "PATH:" << path << " has no files!" << std::endl;
            retImageSender = -1;
            return;
        }
        do {
            for (auto &file : files) {
                (void)flag;
                if (1 == SwitchFlag) {
                    file = "";
                }
                if (file.empty()) {
                    std::cerr << "File not exist,or corrupt.path:" << file << std::endl;
                    retImageSender = -1;
                    return;
                }
                if (!ConfigManage::FileExist(file)) {
                    std::cout << file << " file is not exist!" << std::endl;
                    retImageSender = -1;
                    return;
                }
                bool result = CallProcessing(file, seq);
                if (!result) {
                    retImageSender = -1;
                    return;
                }
            }
        } while (isLoop);
#ifdef SAVE_SENDER_FILE
        if (fclose(fpYuv) == -1) {
            std::cout << "fclose fpYuv failed!" << std::endl;
            retImageSender = -1;
            return;
        }
#endif
        retImageSender = 0;
    }

private:
    void HandleFrequency()
    {
        const int32_t sleepTimeIntervalMs = 1000000;
        if (g_comPara.frequency != "") {
            int32_t freq = atoi(g_comPara.frequency.c_str());
            if (freq != 0) {
                int32_t sleepTime = sleepTimeIntervalMs / freq;
                usleep(sleepTime);
            }
        } else {
            // 30h 1000000微秒
            usleep(sleepTimeIntervalMs / 30); // 30hz
        }
    }

    bool CallProcessing(std::string &file, uint32_t seq)
    {
        cv::Mat YUV;
        cv::Mat BGR = cv::imread(file, cv::IMREAD_COLOR);
        try {
            if (imgSize.width != BGR.cols || imgSize.height != BGR.rows) {
                cv::resize(BGR, BGR, imgSize);
            }
            cvtColor(BGR, YUV, cv::COLOR_BGR2YUV_I420);
        } catch (cv::Exception &e) {
            std::cout << e.what() << std::endl;
        }
        int32_t frameSize = BGR.rows * BGR.cols * 3 / 2;
        unsigned char *pFrame = (unsigned char *)malloc(frameSize);
        const int ciTwo = 2;
        if (ciTwo == SwitchFlag) {
            pFrame = nullptr;
        }
        if (pFrame == nullptr) {
            return false;
        }
        if (memset_s(pFrame, frameSize, 0, frameSize) != 0) {
            return false;
        }
        memcpy_s(pFrame, frameSize, YUV.data, frameSize);
        auto imagePub = dataSkeleton->cameraDecodedMbufEvent.Allocate();
        imagePub->CameraHeader.FrameId = frameID;
        imagePub->CameraHeader.Seq = seq;
        imagePub->Width = BGR.cols;
        imagePub->Height = BGR.rows;
        imagePub->DataSize = frameSize;
        imagePub->UdpData.assign(pFrame, pFrame + imagePub->DataSize);
#ifdef SAVE_SENDER_FILE
        (void)fwrite(pFrame, 1, imagePub->DataSize, fpYuv);
#endif
        if (g_comPara.time.empty()) {
            timeval now;
            gettimeofday(&now, NULL);
            imagePub->CameraHeader.Stamp.Sec = now.tv_sec;
            imagePub->CameraHeader.Stamp.Nsec = now.tv_usec * 1000U;
        } else {
            time_t timeStamp = ConvertTimeStr2TimeStamp(g_comPara.time);
            auto t1 = std::chrono::high_resolution_clock::now();
            int64_t duration = (t1 - sec).count() / 1000000000.0;
            imagePub->CameraHeader.Stamp.Sec = timeStamp + duration;
        }
        const int ciThree = 3;
        if (ciThree != SwitchFlag) {
            dataSkeleton->cameraDecodedMbufEvent.Send(move(imagePub));
        }
        HandleFrequency();
        return true;
    }

private:
    std::string sourceYuvPath {};
    FILE *fpYuv { nullptr };
    std::chrono::high_resolution_clock::time_point sec {}; // -t used
};
#endif // IMAGE_SENDER_H
